package team.lhc.cms.components.security.service.impl;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import team.lhc.cms.components.security.service.WeChatService;
import team.lhc.cms.components.security.utils.Jcode2SessionUtil;
import team.lhc.cms.components.security.utils.JwtTokenUtils;
import team.lhc.cms.entity.Guard;
import team.lhc.cms.entity.Proprietor;
import team.lhc.cms.entity.User;
import team.lhc.cms.mapper.GuardMapper;
import team.lhc.cms.mapper.ProprietorMapper;
import team.lhc.cms.mapper.UserMapper;
import team.lhc.cms.util.JsonResult;
import team.lhc.cms.util.RedisUtil;
import java.util.*;

/**
 * @author 文
 * @description 微信服务实现类
 */
@Service
@Slf4j
public class WeChatServiceImpl implements WeChatService {

    @Value("${weChat.appid}")
    private String appid;

    @Value("${weChat.secret}")
    private String secret;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ProprietorMapper proprietorMapper;

    @Autowired
    private GuardMapper guardMapper;

    /**
     * 微信登录
     * @author 文
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    public String weChatLogin(String code) throws Exception{
        //获取从微信官方服务器后台得到的东西并转换成json格式
        JSONObject sessionInfo = JSONObject.parseObject(jcode2Session(code));

        //验证信息是否空值,若是则code无效
        Assert.notNull(sessionInfo,"code 无效");
        //验证信息是否返回错误,若是则code有误
        if (sessionInfo.getInteger("errcode") != null){
            throw new IllegalArgumentException(sessionInfo.getString("errmsg"));
        }

        // code正常,获取用户唯一标识符openid成功
        User user = userMapper.findByOpenId(sessionInfo.getString("openid"));
        Map<String,Object> map = new HashMap<>();

        //查看用户是否存在
        if (user == null){
            //不存在则创建,并设置标识为"未完善信息"
            user = new User();
            user.setUsername("未设置昵称");
            user.setIsLocked(0);
            user.setRole("ROLE_VISITOR");
            user.setOpenid(sessionInfo.getString("openid"));
            userMapper.save(user);
        }

        //检查用户是否完善信息并标识用户角色
        if (user.getRole() == null){
            //若用户角色为空,则为解绑用户
            user.setRole("ROLE_VISITOR");
            map.put("isCompleted",0);
            map.put("roleFlag","-1");
        }else if ("ROLE_VISITOR".equals(user.getRole())){
            //当用户角色为游客时,即未完善信息
            map.put("isCompleted",0);
            map.put("roleFlag","-1");
        }else if ("ROLE_PROPRIETOR".equals(user.getRole())){
            //若身份是业主,但在业主表找不到对应uid,则为未绑定
            Proprietor pro = proprietorMapper.findByUid(user.getId());
            map.put("isCompleted",pro == null ? 0 : 1);
            //处理返回值
            map.put("roleFlag","0");
        }else if ("ROLE_GUARD".equals(user.getRole())){
            //若身份是保安,但在保安表找不到对应uid,则为未绑定
            Guard guard = guardMapper.findByUid(user.getId());
            map.put("isCompleted",guard == null ? 0 : 1);
            //处理返回值
            map.put("roleFlag","1");
        }else {
            return JsonResult.failed("用户角色异常,请联系物管处");
        }

        //检查账号是否被锁定(仅判断已完善信息的用户)
        if ((Integer) map.get("isCompleted") == 1 && user.getIsLocked() != 0){
            //*** 进入此处后不返回token ***
            return JsonResult.failed("账号已被锁定,请联系物管处理");
        }

        //创建token
        String token = JwtTokenUtils.TOKEN_PREFIX + " " + JwtTokenUtils.createToken(user.getUsername(), user.getRole());

        //存入redis（30分钟）(存入username,openid,uid,role)
        map.put("username",user.getUsername());
        map.put("openid",sessionInfo.getString("openid"));
        map.put("uid",user.getId());
        map.put("role",user.getRole());
        redisUtil.hset(token, (HashMap<String, Object>) map,1800000L);

        //整理map后返回(token,isCompleted,username,roleFlag)
        map.put("token",token);
        map.remove("openid");
        map.remove("uid");
        map.remove("role");
        return JsonResult.success(map);
    }

    /**
     * 以绑定微信的手机号来完善用户名
     * @author 文
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public String completeUsername(Map<String, Object> map) throws Exception {
        //请求session_key
        JSONObject sessionInfo = JSONObject.parseObject(jcode2Session((String) map.get("code")));
        //验证是否空值,若是则code无效
        Assert.notNull(sessionInfo,"code 无效");
        //验证是否返回错误,若是则code有误
        Assert.isTrue(0 == sessionInfo.getInteger("errcode"),sessionInfo.getString("errmsg"));


        //获得用户信息
        String userInfo = Jcode2SessionUtil.getUserInfo((String) map.get("encryptedData"), sessionInfo.getString("session_key"), (String) map.get("iv"));
        String phoneNumber = JSONObject.parseObject(userInfo).getString("phoneNumber");

        //根据openid将用户名写到数据库中
        //设置角色,0为业主,1为保安
        Integer role = (Integer) map.get("role");
        userMapper.updateUsernameAndRoleByOpenid(sessionInfo.getString("openid"),phoneNumber,role == 0?"ROLE_PROPRIETOR":"ROLE_GUARD");
        //更新token
        String oldToken = (String) map.get("token");
        String token = JwtTokenUtils.TOKEN_PREFIX + " " + JwtTokenUtils.createToken(phoneNumber, JwtTokenUtils.getUserRole(oldToken));
        redisUtil.delete(oldToken);
        //当设置的角色为保安的时候,则需要物管进行验证
        if (role != 0){
            //*** 进入此处后不返回token ***
            userMapper.updateIsLockByOpenid(sessionInfo.getString("openid"));
            return JsonResult.failed("注册成功,请联系物业进行审核");
        }
        //初始化map,把token为key,uid为value存入redis
        map = new HashMap<>(1);
        map.put("uid",userMapper.findByOpenId(sessionInfo.getString("openid")).getId());
        redisUtil.hset(token, (HashMap<String, Object>) map,1800000L);

        //返回token
        Map<String,Object> data = new HashMap<>();
        data.put("token",token);
        return JsonResult.success(data);
    }

    /**
     * 完善(认证)用户信息
     * @author 文
     * @param nickName
     * @param tel
     * @param idCard
     * @param role
     * @param token
     * @return
     */
    @Override
    public String completeInfo(String nickName, String tel, String idCard, Integer role, String token) {
        Map<String,Object> data = (Map<String, Object>) redisUtil.hget(token);
        String roleInfo = null;

        //验证信息是否存在并进行绑定
        switch (role){
            case 0:
                roleInfo = "ROLE_PROPRIETOR";


                //查找是否存在该信息
                Proprietor proprietor = proprietorMapper.findByTelAndIdCard(tel,idCard);
                if (proprietor != null){
                    //处理已被绑定的用户信息
                    if (proprietor.getUid() != null){
                        return JsonResult.failed("您输入的信息已绑定用户,如有需要请解绑后再进行绑定");
                    }
                    //绑定
                    proprietor.setUid((Integer) data.get("uid"));
                    proprietorMapper.updateUidByTelAndIdCard(proprietor.getUid(),proprietor.getTel(),proprietor.getIdCard());
                }else {
                    return JsonResult.failed("不存在您输入的信息,请重新输入或联系物管处");
                }
                //完善用户名
                userMapper.updateUsernameAndRoleByUid(nickName,roleInfo,(Integer)data.get("uid"));
                break;
            case 1:
                roleInfo = "ROLE_GUARD";


                //查找是否存在该信息
                Guard guard = guardMapper.findByTelAndIdCard(tel,idCard);
                if (guard != null){
                    //处理已被绑定的用户信息
                    if (guard.getUid() != null){
                        return JsonResult.failed("您输入的信息已绑定用户,如有需要请解绑后再进行绑定");
                    }
                    //绑定
                    guard.setUid((Integer) data.get("uid"));
                    guardMapper.updateGuard(guard);
                }else {
                    return JsonResult.failed("不存在您输入的信息,请重新输入或联系物管处");
                }
                //完善用户名
                userMapper.updateUsernameAndRoleByUid(nickName,roleInfo,(Integer) data.get("uid"));
                //上锁,等待物业验证
                userMapper.updateIsLockByUid((Integer)data.get("uid"));
                return JsonResult.failed("注册成功,请联系物业进行审核");
            default:
                return JsonResult.failed("角色非法选取,请重新选择或联系物管处");
        }

        //暂时只有业主能获取新的token
        //返回新的token信息(username,token)
        String newToken = JwtTokenUtils.TOKEN_PREFIX + " " + JwtTokenUtils.createToken(nickName, roleInfo);
        redisUtil.delete(token);
        Map<String,Object> map = new HashMap<>();
        map.put("uid", data.get("uid"));
        redisUtil.hset(token, (HashMap<String, Object>) map,1800000L);
        map.remove("uid");
        map.put("token",newToken);
        map.put("username",nickName);
        map.put("role",role);
        return JsonResult.success(map);
    }

    /**
     * 登录凭证校验(发送请求到微信服务器进行校验)
     * @author 文
     * @param code
     * @return
     * @throws Exception
     */
    private String jcode2Session(String code)throws Exception{
        String sessionInfo = Jcode2SessionUtil.jscode2session(appid,secret,code,"authorization_code");//登录grantType固定
        log.debug(sessionInfo);
        return sessionInfo;
    }


}
